using Microsoft.EntityFrameworkCore;
using WeatherSystem.API.Data;
using WeatherSystem.API.Models;
using WeatherSystem.API.Helpers;

namespace WeatherSystem.API.Services
{
    /// <summary>
    /// 统计服务接口
    /// </summary>
    public interface IStatisticsService
    {
        Task GenerateDailyStatisticsAsync(DateTime date);
        Task<Dictionary<string, object>?> GetDailyStatisticsAsync(Guid cityId, DateTime date);
        Task<List<Dictionary<string, object>>> GetStatisticsRangeAsync(Guid cityId, DateTime startDate, DateTime endDate);
        Task<object> GetWeatherTrendAsync(Guid cityId, int days);
        Task<List<Dictionary<string, object>>> GetCityComparisonAsync(List<Guid> cityIds, DateTime date);
        Task<Dictionary<string, object>?> GetCityStatisticsAsync(Guid cityId, DateTime startDate, DateTime endDate);
        Task CleanupOldStatisticsAsync(int retentionDays);
        Task<StatisticsEntry?> GetStatisticsEntryAsync(Guid cityId, DateTime date, string statisticType = "Daily");
    }

    /// <summary>
    /// 统计服务实现
    /// </summary>
    public class StatisticsService : IStatisticsService
    {
        private readonly WeatherDbContext _context;
        private readonly ILogger<StatisticsService> _logger;
        private readonly IMetricConfigurationService _metricConfigService;

        public StatisticsService(
            WeatherDbContext context,
            ILogger<StatisticsService> logger,
            IMetricConfigurationService metricConfigService)
        {
            _context = context;
            _logger = logger;
            _metricConfigService = metricConfigService;
        }

        /// <summary>
        /// 生成每日统计数据
        /// </summary>
        public async Task GenerateDailyStatisticsAsync(DateTime date)
        {
            var targetDate = date.Date;
            _logger.LogInformation("开始生成 {Date} 的每日统计数据", targetDate.ToString("yyyy-MM-dd"));

            try
            {
                // 获取所有活跃城市
                var cities = await _context.Cities
                    .Where(c => c.IsActive)
                    .ToListAsync();

                int processedCount = 0;
                int errorCount = 0;

                foreach (var city in cities)
                {
                    try
                    {
                        await GenerateCityDailyStatisticsAsync(city.Id, targetDate);
                        processedCount++;
                        _logger.LogDebug("城市 {CityName} 的每日统计生成完成", city.Name);
                    }
                    catch (Exception ex)
                    {
                        errorCount++;
                        _logger.LogError(ex, "生成城市 {CityName} 每日统计时发生错误", city.Name);
                    }
                }

                _logger.LogInformation("每日统计生成完成，处理: {ProcessedCount}, 错误: {ErrorCount}", 
                    processedCount, errorCount);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "生成每日统计数据时发生错误");
                throw;
            }
        }

        /// <summary>
        /// 生成单个城市的每日统计
        /// </summary>
        private async Task GenerateCityDailyStatisticsAsync(Guid cityId, DateTime date)
        {
            var startTime = date.Date;
            var endTime = startTime.AddDays(1);

            // 获取当天的天气数据（EAV模式）
            var weatherDataEntries = await _context.WeatherDataEntries
                .Include(e => e.Metrics)
                .ThenInclude(m => m.Definition)
                .Where(e => e.CityId == cityId && 
                           e.RecordedAt >= startTime && 
                           e.RecordedAt < endTime)
                .OrderBy(e => e.RecordedAt)
                .ToListAsync();

            if (!weatherDataEntries.Any())
            {
                _logger.LogDebug("城市 {CityId} 在 {Date} 没有天气数据", cityId, date.ToString("yyyy-MM-dd"));
                return;
            }

            // 检查是否已存在统计数据
            var existingStats = await _context.StatisticsEntries
                .FirstOrDefaultAsync(s => s.CityId == cityId && s.StatisticDate == date && s.StatisticType == "Daily");

            if (existingStats != null)
            {
                _logger.LogDebug("城市 {CityId} 在 {Date} 的统计数据已存在，跳过生成", 
                    cityId, date.ToString("yyyy-MM-dd"));
                return;
            }

            // 计算动态统计数据
            var statisticsEntry = await CalculateDynamicStatistics(weatherDataEntries, cityId, date);

            // 保存统计数据
            _context.StatisticsEntries.Add(statisticsEntry);
            await _context.SaveChangesAsync();

            _logger.LogDebug("城市 {CityId} 在 {Date} 的统计数据已生成", 
                cityId, date.ToString("yyyy-MM-dd"));
        }

        /// <summary>
        /// 计算动态统计数据（EAV模式）
        /// </summary>
        private async Task<StatisticsEntry> CalculateDynamicStatistics(List<WeatherDataEntry> weatherDataEntries, Guid cityId, DateTime date)
        {
            var statisticsEntry = new StatisticsEntry
            {
                CityId = cityId,
                StatisticType = "Daily",
                StatisticDate = date,
                DataPointCount = weatherDataEntries.Count
            };

            var statisticValues = new List<StatisticValue>();

            // 获取所有涉及的指标类型
            var allMetricKeys = weatherDataEntries
                .SelectMany(e => e.Metrics)
                .Select(m => m.MetricKey)
                .Distinct()
                .ToList();

            foreach (var metricKey in allMetricKeys)
            {
                var metricDefinition = await _context.MetricDefinitions
                    .FirstOrDefaultAsync(m => m.Key == metricKey);
                    
                if (metricDefinition == null) continue;

                if (metricDefinition.DataType.ToLower() == "decimal")
                {
                    var values = GetDecimalValues(weatherDataEntries, metricKey);
                    if (values.Any())
                    {
                        // 平均值
                        statisticValues.Add(new StatisticValue
                        {
                            StatisticsEntryId = statisticsEntry.Id,
                            MetricKey = metricKey,
                            AggregationType = "avg",
                            RawValue = Math.Round(values.Average(), 2).ToString(),
                            DataType = "decimal"
                        });

                        // 最大值
                        statisticValues.Add(new StatisticValue
                        {
                            StatisticsEntryId = statisticsEntry.Id,
                            MetricKey = metricKey,
                            AggregationType = "max",
                            RawValue = values.Max().ToString(),
                            DataType = "decimal"
                        });

                        // 最小值
                        statisticValues.Add(new StatisticValue
                        {
                            StatisticsEntryId = statisticsEntry.Id,
                            MetricKey = metricKey,
                            AggregationType = "min",
                            RawValue = values.Min().ToString(),
                            DataType = "decimal"
                        });
                    }
                }
                else if (metricDefinition.DataType.ToLower() == "string")
                {
                    var stringValues = GetStringValues(weatherDataEntries, metricKey);
                    if (stringValues.Any())
                    {
                        var dominant = stringValues
                            .GroupBy(x => x)
                            .OrderByDescending(g => g.Count())
                            .First().Key;

                        statisticValues.Add(new StatisticValue
                        {
                            StatisticsEntryId = statisticsEntry.Id,
                            MetricKey = metricKey,
                            AggregationType = "dominant",
                            RawValue = dominant,
                            DataType = "string"
                        });
                    }
                }
            }

            statisticsEntry.Values = statisticValues;
            return statisticsEntry;
        }

        /// <summary>
        /// 从EAV数据中提取数值型指标
        /// </summary>
        private List<decimal> GetDecimalValues(List<WeatherDataEntry> entries, string metricKey)
        {
            var values = new List<decimal>();
            foreach (var entry in entries)
            {
                var metric = entry.Metrics.FirstOrDefault(m => m.MetricKey == metricKey);
                if (metric != null && decimal.TryParse(metric.RawValue, out var value))
                {
                    values.Add(value);
                }
            }
            return values;
        }

        /// <summary>
        /// 从EAV数据中提取字符型指标
        /// </summary>
        private List<string> GetStringValues(List<WeatherDataEntry> entries, string metricKey)
        {
            var values = new List<string>();
            foreach (var entry in entries)
            {
                var metric = entry.Metrics.FirstOrDefault(m => m.MetricKey == metricKey && !string.IsNullOrEmpty(m.RawValue));
                if (metric != null)
                {
                    values.Add(metric.RawValue);
                }
            }
            return values;
        }

        /// <summary>
        /// 获取每日统计数据（动态结构）
        /// </summary>
        public async Task<Dictionary<string, object>?> GetDailyStatisticsAsync(Guid cityId, DateTime date)
        {
            var statisticsEntry = await GetStatisticsEntryAsync(cityId, date);
            if (statisticsEntry == null) return null;

            var result = new Dictionary<string, object>
            {
                ["id"] = statisticsEntry.Id,
                ["cityId"] = statisticsEntry.CityId,
                ["statisticType"] = statisticsEntry.StatisticType,
                ["statisticDate"] = statisticsEntry.StatisticDate,
                ["dataPointCount"] = statisticsEntry.DataPointCount,
                ["createdAt"] = statisticsEntry.CreatedAt
            };

            foreach (var value in statisticsEntry.Values)
            {
                var key = $"{value.MetricKey}_{value.AggregationType}";
                result[key] = ConvertRawValueToTyped(value.RawValue, value.DataType);
            }

            return result;
        }

        /// <summary>
        /// 获取时间范围内的统计数据（动态结构）
        /// </summary>
        public async Task<List<Dictionary<string, object>>> GetStatisticsRangeAsync(
            Guid cityId, DateTime startDate, DateTime endDate)
        {
            var statisticsEntries = await _context.StatisticsEntries
                .Include(s => s.City)
                .Include(s => s.Values)
                .ThenInclude(v => v.Definition)
                .Where(s => s.CityId == cityId && 
                           s.StatisticDate >= startDate.Date && 
                           s.StatisticDate <= endDate.Date)
                .OrderBy(s => s.StatisticDate)
                .ToListAsync();

            var result = new List<Dictionary<string, object>>();
            foreach (var entry in statisticsEntries)
            {
                var dict = new Dictionary<string, object>
                {
                    ["id"] = entry.Id,
                    ["cityId"] = entry.CityId,
                    ["statisticType"] = entry.StatisticType,
                    ["statisticDate"] = entry.StatisticDate,
                    ["dataPointCount"] = entry.DataPointCount
                };

                foreach (var value in entry.Values)
                {
                    var key = $"{value.MetricKey}_{value.AggregationType}";
                    dict[key] = ConvertRawValueToTyped(value.RawValue, value.DataType);
                }

                result.Add(dict);
            }

            return result;
        }

        /// <summary>
        /// 获取天气趋势数据
        /// </summary>
        public async Task<object> GetWeatherTrendAsync(Guid cityId, int days)
        {
            var endDate = DateTime.Today;
            var startDate = endDate.AddDays(-days + 1);

            var statistics = await GetStatisticsRangeAsync(cityId, startDate, endDate);

            return new Dictionary<string, object>
            {
                ["cityId"] = cityId,
                ["startDate"] = startDate,
                ["endDate"] = endDate,
                ["dailyStatistics"] = statistics,
                ["temperatureTrend"] = CalculateMetricTrend(statistics, "temperature").ToString(),
                ["humidityTrend"] = CalculateMetricTrend(statistics, "humidity").ToString(),
                ["pressureTrend"] = CalculateMetricTrend(statistics, "pressure").ToString()
            };
        }

        /// <summary>
        /// 获取城市对比数据（动态结构）
        /// </summary>
        public async Task<List<Dictionary<string, object>>> GetCityComparisonAsync(
            List<Guid> cityIds, DateTime date)
        {
            var statistics = await _context.StatisticsEntries
                .Include(s => s.City)
                .Include(s => s.Values)
                .Where(s => cityIds.Contains(s.CityId) && s.StatisticDate == date.Date)
                .ToListAsync();

            return statistics.Select(s => {
                var dict = new Dictionary<string, object>
                {
                    ["cityId"] = s.CityId,
                    ["cityName"] = s.City?.Name ?? "Unknown",
                    ["date"] = s.StatisticDate,
                    ["dataPointCount"] = s.DataPointCount
                };
                
                foreach (var value in s.Values)
                {
                    var key = $"{value.MetricKey}_{value.AggregationType}";
                    dict[key] = ConvertRawValueToTyped(value.RawValue, value.DataType);
                }
                
                return dict;
            }).ToList();
        }

        /// <summary>
        /// 获取统计条目
        /// </summary>
        public async Task<StatisticsEntry?> GetStatisticsEntryAsync(Guid cityId, DateTime date, string statisticType = "Daily")
        {
            return await _context.StatisticsEntries
                .Include(s => s.City)
                .Include(s => s.Values)
                .ThenInclude(v => v.Definition)
                .FirstOrDefaultAsync(s => s.CityId == cityId && s.StatisticDate == date.Date && s.StatisticType == statisticType);
        }

        /// <summary>
        /// 清理旧的统计数据
        /// </summary>
        public async Task CleanupOldStatisticsAsync(int retentionDays)
        {
            var cutoffDate = DateTime.Today.AddDays(-retentionDays);
            
            var oldStatistics = await _context.StatisticsEntries
                .Where(s => s.StatisticDate < cutoffDate)
                .ToListAsync();

            if (oldStatistics.Any())
            {
                _context.StatisticsEntries.RemoveRange(oldStatistics);
                await _context.SaveChangesAsync();
                
                _logger.LogInformation("已清理 {Count} 条过期统计数据（保留天数: {RetentionDays}）", 
                    oldStatistics.Count, retentionDays);
            }
        }

        /// <summary>
        /// 将原始值转换为相应的类型
        /// </summary>
        private object ConvertRawValueToTyped(string rawValue, string dataType)
        {
            return dataType.ToLower() switch
            {
                "decimal" => decimal.TryParse(rawValue, out var d) ? d : 0m,
                "int" => int.TryParse(rawValue, out var i) ? i : 0,
                "boolean" => bool.TryParse(rawValue, out var b) && b,
                _ => rawValue
            };
        }

        /// <summary>
        /// 从统计值集合中获取数值型指标
        /// </summary>
        private decimal GetStatisticValue(ICollection<StatisticValue> values, string metricKey, string aggregationType)
        {
            var value = values.FirstOrDefault(v => v.MetricKey == metricKey && v.AggregationType == aggregationType);
            return value != null && decimal.TryParse(value.RawValue, out var result) ? result : 0m;
        }

        /// <summary>
        /// 从统计值集合中获取字符型指标
        /// </summary>
        private string GetStatisticStringValue(ICollection<StatisticValue> values, string metricKey, string aggregationType)
        {
            var value = values.FirstOrDefault(v => v.MetricKey == metricKey && v.AggregationType == aggregationType);
            return value?.RawValue ?? string.Empty;
        }

        /// <summary>
        /// 计算指标趋势（通用方法）
        /// </summary>
        private TrendDirection CalculateMetricTrend(List<Dictionary<string, object>> statistics, string metricKey)
        {
            if (statistics.Count < 2) return TrendDirection.Stable;

            var avgKey = $"{metricKey}_avg";
            var values = statistics
                .Where(s => s.ContainsKey(avgKey))
                .Select(s => Convert.ToDecimal(s[avgKey]))
                .ToList();

            if (values.Count < 2) return TrendDirection.Stable;

            var firstHalf = values.Take(values.Count / 2).Average();
            var secondHalf = values.Skip(values.Count / 2).Average();
            var difference = secondHalf - firstHalf;

            var threshold = metricKey switch
            {
                "temperature" => 1m,
                "humidity" => 5m,
                "pressure" => 2m,
                _ => 1m
            };

            return difference switch
            {
                var d when d > threshold => TrendDirection.Rising,
                var d when d < -threshold => TrendDirection.Falling,
                _ => TrendDirection.Stable
            };
        }

        /// <summary>
        /// 获取城市统计数据（EAV结构）
        /// </summary>
        public async Task<Dictionary<string, object>?> GetCityStatisticsAsync(Guid cityId, DateTime startDate, DateTime endDate)
        {
            try
            {
                var city = await _context.Cities.FindAsync(cityId);
                if (city == null)
                {
                    return null;
                }

                var statisticsEntries = await _context.StatisticsEntries
                    .Include(s => s.Values)
                    .Where(s => s.CityId == cityId && s.StatisticDate >= startDate.Date && s.StatisticDate <= endDate.Date)
                    .ToListAsync();

                if (!statisticsEntries.Any())
                {
                    return new Dictionary<string, object>
                    {
                        ["cityId"] = cityId,
                        ["cityName"] = city.Name,
                        ["startDate"] = startDate,
                        ["endDate"] = endDate,
                        ["dataCount"] = 0
                    };
                }

                var aggregatedStats = new Dictionary<string, object>
                {
                    ["cityId"] = cityId,
                    ["cityName"] = city.Name,
                    ["startDate"] = startDate,
                    ["endDate"] = endDate,
                    ["dataCount"] = statisticsEntries.Sum(s => s.DataPointCount)
                };

                // 聚合所有统计值
                var allValues = statisticsEntries.SelectMany(s => s.Values).ToList();
                var metricGroups = allValues.GroupBy(v => v.MetricKey);

                foreach (var group in metricGroups)
                {
                    var metricKey = group.Key;
                    var avgValues = group.Where(v => v.AggregationType == "avg").ToList();
                    var maxValues = group.Where(v => v.AggregationType == "max").ToList();
                    var minValues = group.Where(v => v.AggregationType == "min").ToList();

                    if (avgValues.Any())
                    {
                        var avgMetrics = avgValues
                            .Select(v => decimal.TryParse(v.RawValue, out var d) ? d : 0m)
                            .Where(v => v != 0m)
                            .ToList();
                        if (avgMetrics.Any())
                        {
                            aggregatedStats[$"avg{MetricsHelper.ToPascalCase(metricKey)}"] = Math.Round(avgMetrics.Average(), 2);
                        }
                    }

                    if (maxValues.Any())
                    {
                        var maxMetrics = maxValues
                            .Select(v => decimal.TryParse(v.RawValue, out var d) ? d : 0m)
                            .ToList();
                        if (maxMetrics.Any())
                        {
                            aggregatedStats[$"max{MetricsHelper.ToPascalCase(metricKey)}"] = maxMetrics.Max();
                        }
                    }

                    if (minValues.Any())
                    {
                        var minMetrics = minValues
                            .Select(v => decimal.TryParse(v.RawValue, out var d) ? d : 0m)
                            .ToList();
                        if (minMetrics.Any())
                        {
                            aggregatedStats[$"min{MetricsHelper.ToPascalCase(metricKey)}"] = minMetrics.Min();
                        }
                    }
                }

                return aggregatedStats;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取城市统计数据失败: CityId={CityId}", cityId);
                throw;
            }
        }
    }

    /// <summary>
    /// 天气趋势数据
    /// </summary>
    public class WeatherTrendData
    {
        public Guid CityId { get; set; }
        public DateTime StartDate { get; set; }
        public DateTime EndDate { get; set; }
        public List<Dictionary<string, object>> DailyStatistics { get; set; } = new();
        public TrendDirection TemperatureTrend { get; set; }
        public TrendDirection HumidityTrend { get; set; }
        public TrendDirection PressureTrend { get; set; }
    }

    /// <summary>
    /// 城市对比数据
    /// </summary>
    public class CityComparisonData
    {
        public Guid CityId { get; set; }
        public string CityName { get; set; } = string.Empty;
        public DateTime Date { get; set; }
        public decimal AvgTemperature { get; set; }
        public decimal MaxTemperature { get; set; }
        public decimal MinTemperature { get; set; }
        public decimal AvgHumidity { get; set; }
        public decimal AvgPressure { get; set; }
        public decimal AvgWindSpeed { get; set; }
        public string DominantWeatherCondition { get; set; } = string.Empty;
    }

    /// <summary>
    /// 趋势方向枚举
    /// </summary>
    public enum TrendDirection
    {
        Rising,
        Falling,
        Stable
    }
}